package com.jusfoun.communication.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jusfoun.communication.constant.MessageConstant;
import com.jusfoun.communication.constant.UserConstant;
import com.jusfoun.communication.model.Message;
import com.jusfoun.communication.model.User;
import com.jusfoun.communication.service.MessageService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket消息处理类
 *
 * @author player six
 * @email jslcylcy@163.com
 * @create 2017-10-12 16:18
 **/
@Component
public class WebSocketEndPoint extends TextWebSocketHandler {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketEndPoint.class);

    /**
     * 存储所有连接的session
     */
    private Map<String, Map<String, WebSocketSession>> sessions = new ConcurrentHashMap<>();

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MessageService messageService;

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
        String context = message.getPayload();
        Map<String, Object> attributes = session.getAttributes();
        Object appId = attributes.get("appId");
        Object userName = attributes.get("userName");
        logger.info("收到消息,appId:" + appId + ",userName:" + userName + ",message:" + context);
        if (null == appId || null == userName || null == sessions.get(appId.toString())) {
            logger.info("异常websocket连接");
            session.close();
            return;
        }
        if (StringUtils.isNotBlank(context)) {
            messageService.handleMessage(session, appId.toString(), userName.toString(), context);
        }
    }

    /**
     * 连接建立之后的相关操作(将session增加到map中)
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
        Map<String, Object> attributes = session.getAttributes();
        Object appId = attributes.get("appId");
        Object userName = attributes.get("userName");
        if (null == appId || "".equals(appId.toString().trim()) || null == userName || "".equals(userName.toString().trim())) {
            logger.info("异常websocket连接");
            session.close();
            return;
        }
        Map<String, WebSocketSession> map = sessions.get(appId.toString());
        if (map == null) {
            synchronized (sessions) {
                map = sessions.get(appId.toString());
                if (map == null) {
                    map = new ConcurrentHashMap<>();
                    sessions.put(appId.toString(), map);
                }
            }
        }
        WebSocketSession orgin = map.put(userName.toString(), session);
        if (null != orgin && orgin.isOpen()) {
            //处理重复登录,剔除用户
            orgin.sendMessage(new TextMessage(objectMapper.writeValueAsString(new Message(MessageConstant.CODE_REPEAT_KICK))));
            orgin.close();
        }
        //检查离线消息,发送用户的离线消息
        messageService.sendOffLineMsg(appId.toString(), userName.toString());
        messageService.dealLoginMsg(appId.toString(), userName.toString());
    }

    /**
     * 连接关闭时需要手动从sessions中删除原有连接
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        Map<String, Object> attributes = session.getAttributes();
        Object appId = attributes.get("appId");
        Object userName = attributes.get("userName");
        if (null != appId && null != userName) {
            Map<String, WebSocketSession> map = sessions.get(appId.toString());
            if (null != map) {
                map.remove(userName.toString());
                logger.info("appId:" + appId + ",userName:" + userName + "下线");
            }
            messageService.dealLogoutMsg(appId.toString(), userName.toString());
        }
    }


    /**
     * 推送消息给指定用户
     *
     * @param message
     * @return
     */
    public boolean sendMsg(Message message) {
        Map<String, WebSocketSession> map = sessions.get(message.getAppId());
        if (null != map) {
            WebSocketSession session = map.get(message.getTo());
            if (null != session && session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
                    return true;
                } catch (IOException e) {
                    logger.error("发送消息失败", e);
                    return false;
                }
            }
            logger.info("用户:" + message.getTo() + ",不在线---1");
            return false;
        }
        logger.info("用户:" + message.getTo() + ",不在线---2");
        return false;
    }

    /**
     * 校验当前用户的在线离线状态
     *
     * @param user
     */
    public User checkUserStatus(User user) {
        Map<String, WebSocketSession> map = sessions.get(user.getAppId());
        if (map != null) {
            WebSocketSession session = map.get(user.getUserName());
            if (session != null && session.isOpen()) {
                user.setStatus(UserConstant.STATUS_ONLINE);
                return user;
            }
        }
        user.setStatus(UserConstant.STATUS_OFFLINE);
        return user;
    }
}
